package com.xsomnus.open.imv2.protocol;

import com.xsomnus.open.imv2.protocol.request.*;
import com.xsomnus.open.imv2.protocol.response.*;
import com.xsomnus.open.imv2.serialize.Serializer;
import com.xsomnus.open.imv2.serialize.impl.FastJSONSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;

import java.util.HashMap;
import java.util.Map;

import static com.xsomnus.open.imv2.protocol.Command.*;

/**
 * @author @xsomnus666_xiawenye★
 * @since 2019/4/24 0024 17:04
 * 当你发现自己的才华撑不起野心时，就请安静下来学习吧
 * +---------------+---------+----------+--------+--------+----------------+
 * |      魔数      |  版本号  | 序列化算法 |  指令  | 数据长度 |       数据     |
 * |   0x19921110  |    1    |    1     |   1   |  4bit   |      N bit    |
 * +---------------+---------+----------+-------+---------+---------------+
 */
public class PacketCodec {

    public static final int MAGIC_NUMBER = 0x19921110;
    public static final PacketCodec INSTANCE = new PacketCodec();

    private final Map<Byte, Class<? extends Packet>> packetTypeMap;
    private final Map<Byte, Serializer> serializerMap;

    private PacketCodec() {
        packetTypeMap = new HashMap<>();
        packetTypeMap.put(LOGIN_REQUEST, LoginRequestPacket.class);
        packetTypeMap.put(LOGIN_RESPONSE, LoginResponsePacket.class);
        packetTypeMap.put(MESSAGE_REQUEST, MessageRequestPacket.class);
        packetTypeMap.put(MESSAGE_RESPONSE, MessageResponsePacket.class);
        packetTypeMap.put(LOGOUT_REQUEST, LogoutRequestPacket.class);
        packetTypeMap.put(LOGOUT_RESPONSE, LogoutRequestPacket.class);
        packetTypeMap.put(CREATE_GROUP_REQUEST, CreateGroupRequestPacket.class);
        packetTypeMap.put(CREATE_GROUP_RESPONSE, CreateGroupResponsePacket.class);
        packetTypeMap.put(JOIN_GROUP_REQUEST, JoinGroupRequestPacket.class);
        packetTypeMap.put(JOIN_GROUP_RESPONSE, JoinGroupResponsePacket.class);
        packetTypeMap.put(QUIT_GROUP_REQUEST, QuitGroupRequestPacket.class);
        packetTypeMap.put(QUITE_GROUP_RESPONSE, QuitGroupResponsePacket.class);
        packetTypeMap.put(LIST_GROUP_MEMBER_REQUEST, ListGroupMemberRequestPacket.class);
        packetTypeMap.put(LIST_GROUP_MEMBER_RESPOSNE, ListGroupMemberResponsePacket.class);

        serializerMap = new HashMap<>();
        Serializer serializer = new FastJSONSerializer();
        serializerMap.put(serializer.getSerializerAlgorithm(), serializer);
    }

    /**
     * 获取指令类型
     */
    private Class<? extends Packet> getRequestType(byte command) {
        return packetTypeMap.get(command);
    }

    /**
     * 获取指定的序列化工具
     */
    private Serializer getSerializer(byte serializeAlgorithm) {
        return serializerMap.get(serializeAlgorithm);
    }

    /**
     * @param packet 数据包
     * @return ByteBuf
     */
    public ByteBuf encode(Packet packet) {
        // (1) 创建ByteBuf对象
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
        // (2) java对象序列化
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        // (3) 将packet编码成既定的协议格式
        byteBuf.writeInt(MAGIC_NUMBER);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);
        return byteBuf;
    }

    public void encode(ByteBuf byteBuf, Packet packet) {
        // 1. 序列化 java 对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);

        // 2. 实际编码过程
        byteBuf.writeInt(MAGIC_NUMBER);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);
    }

    public ByteBuf encode(ByteBufAllocator allocator, Packet packet) {

        // 1. 创建 ByteBuf 对象
        ByteBuf byteBuf = allocator.ioBuffer();
        // 2. 序列化 java 对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        // 3. 实际编码过程
        byteBuf.writeInt(MAGIC_NUMBER);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);

        return byteBuf;
    }

    /**
     * @param byteBuf 字节buffer对象
     */
    public Packet decode(ByteBuf byteBuf) {
        // (1) 跳过魔数
        byteBuf.skipBytes(4);
        // (2) 跳过版本号
        byteBuf.skipBytes(1);
        // (3) 序列化算法
        byte serializerAlgorithm = byteBuf.readByte();
        // (4) 指令
        byte command = byteBuf.readByte();
        // (5) 获取数据包长度
        int length = byteBuf.readInt();
        // (6) 获取packet二进制数据
        byte[] bytes = new byte[length];
        byteBuf.readBytes(bytes);

        Class<? extends Packet> requestType = getRequestType(command);
        Serializer serializer = getSerializer(serializerAlgorithm);

        // (7) 调用反序列工具
        if (requestType != null && serializer != null) {
            return serializer.deserializer(requestType, bytes);
        }

        return null;
    }

}
